#include "YasDownloadAgent.h"
#include "YasDownloadConfig.h"

namespace yas{

YasDownloadAgent::YasDownloadAgent(const YasDownloadConfig *const conf):
		config(conf),
		target_url(conf->getBaseURL()),
		port(conf->getPort())
{
}

YasDownloadAgent::~YasDownloadAgent()
{
	closeSocket();
}


const YasDownloadConfig* YasDownloadAgent::getDownloadConfig() const
{
	return config;
}

int YasDownloadAgent::processConfiguration()
{
	const std::vector<std::string>& configPaths = config->getPaths();
	size_t len = configPaths.size();
	for(size_t i=0; i<len; i++)
	{
		downloadSync(config->getBaseURL() + configPaths.at(i));
		std::cout << config->getBaseURL() + configPaths.at(i) << std::endl;
		std::cout << getDownloadedContent();
		std::cout << std::endl << std::endl;
	}

	return Yas::YAS_OK;
}



std::string YasDownloadAgent::getDownloadedContent()
{
	std::stringstream& contentstream = getContentStream();

	if(!contentstream.bad())
		return contentstream.str();
	else
		return std::string("[ERROR]");
}

void YasDownloadAgent::flushContent()
{
	getContentStream().flush();
}

std::string YasDownloadAgent::createHttpHeader(
		const std::string & httpMethod,
		const std::string & url,
		const std::string & httpVersion,
		const std::string & acceptClause,
		const std::string & acceptEncoding,
		const std::string & userAgent,
		const std::string & connection
) const
{
	const std::string lf = "\n";

	std::stringstream httpHeader("");

	httpHeader <<  "GET " << url <<
			" HTTP/" << httpVersion << lf <<
			"Accept: " << acceptClause << lf <<
			"Accept-Language: En" << lf <<
			"Accept-Encoding: "<< acceptEncoding << lf <<
			"User-Agent: " << userAgent << lf <<
			"Connection: " << connection << lf <<
			lf;

	std::string header = httpHeader.str();
	std::cout << "HEADER == " << header;
	return header;
}

int YasDownloadAgent::getSocketFd() const
{
	return this->socketfd;
}

int YasDownloadAgent::sendSocketData(const std::string & data)
{
	if(send(getSocketFd(), const_cast<char*>(data.c_str()), data.length(), 0) == -1)
	{
		doLog("Cannot send data to socket", Yas::YAS_ERROR);
		return Yas::YAS_ERROR;
	}
	else
		return Yas::YAS_OK;
}

int YasDownloadAgent::setSocketFd(int socketFd)
{
	if(socketFd < 0)
	{
		doLog("Invalid socket value ", Yas::YAS_ERROR);
		return Yas::YAS_ERROR;
	}
	else
	{
		this->socketfd = socketFd;
		return Yas::YAS_OK;
	}
}
void YasDownloadAgent::closeSocket()
{
	close(this->getSocketFd());
}

int YasDownloadAgent::recvSocketData()
{
	char dataBuffer[YasDownloadAgent::MAXDATASIZE];

	int bytes_rec = recv(getSocketFd(), dataBuffer, YasDownloadAgent::MAXDATASIZE-1, 0);

	if(bytes_rec == -1)
	{
		doLog("Cannot get data from socket", Yas::YAS_ERROR);
		return Yas::YAS_ERROR;
	}
	else
	{
		dataBuffer[bytes_rec] = '\0';
		this->contentStream << std::string(dataBuffer);
		return Yas::YAS_OK;
	}
}

std::string YasDownloadAgent::getPort() const
{
	std::stringstream sstr("");
	sstr << this->port;
	return sstr.str();
}

std::string YasDownloadAgent::getTargetUrl() const
{
	return this->target_url;
}

int YasDownloadAgent::connectSocket()
{
	int sockfd;
	struct addrinfo hints, *servinfo, *p;
	int rv;

	memset(&hints, 0, sizeof hints);
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

	if ((rv = getaddrinfo(const_cast<const char*>(getTargetUrl().c_str()) ,
			const_cast<const char*>(getPort().c_str()),
			&hints,
			&servinfo)) != 0)
	{
		std::stringstream errorStr("");
		errorStr << "Cannot get addrinfo " <<  gai_strerror(rv);
		doLog(errorStr.str(), Yas::YAS_ERROR);
		return Yas::YAS_ERROR;
	}

	// loop through all the results and connect to the first we can
	for(p = servinfo; p ; p = p->ai_next)
	{
		if ((sockfd = socket(p->ai_family, p->ai_socktype,
				p->ai_protocol)) == -1) {
			doLog("Cannot get socket", Yas::YAS_ERROR);
			continue;
		}
		if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
			close(sockfd);
			doLog("Cannot connect to socket", Yas::YAS_ERROR);
			continue;
		}
		break;
	}
	if (!p)
	{
		doLog("Cannot get server info", Yas::YAS_ERROR);
		return Yas::YAS_ERROR;
	}

	freeaddrinfo(servinfo);// all done with this structure

	setSocketFd(sockfd);
	return Yas::YAS_OK;
}


int YasDownloadAgent::downloadSync(const std::string &fullUrl)
{
	if(!isConnected())
	{
		if(connectSocket() == Yas::YAS_ERROR)
		{
			doLog("Cannot connect to " + fullUrl, Yas::YAS_ERROR);
			return Yas::YAS_ERROR;
		}
		else
		{
			setIsConnected(true);
		}
	}

	std::string httpHeader = createHttpHeader("GET",
			fullUrl,
			"1.1",
			"text/html, image/gif, image/x-xbitmap, image/jpeg, image/pjpeg",
			"gzip, deflate",
			"YAS",
			"Keep-Alive");

	if(sendSocketData(const_cast<char*>(httpHeader.c_str())) == Yas::YAS_ERROR)
		return Yas::YAS_ERROR;

	if(recvSocketData() == Yas::YAS_ERROR)
		return Yas::YAS_ERROR;

	return Yas::YAS_OK;
}

std::stringstream& YasDownloadAgent::getContentStream()
{
	return this->contentStream;
}

}
